import { IControllerRouter, IMethodRouter, Method } from "./models";
import { Express, Router } from "express";
import glob from "glob";
import { resolve } from "path";
import { RequestHandler } from "express-serve-static-core";

const controllerMap: Map<string, IControllerRouter> = new Map<string, IControllerRouter>();
const methodArray: IMethodRouter[] = [];

class Route {
    private app: Express;
    private readonly router: Router;
    constructor(app: Express) {
        this.app = app;
        this.router = Router();
    }

    init(apiPath: string) {
        // 这里其实也可以通过Reflect.metadata的方式来实现，无非就方法装饰器执行的时候先把数据以definedMetaData的方式定义在方法上，
        // 由于类中方法上的装饰器执行在前，类上的装饰器执行在后，所以@controller装饰器执行的时候就能拿到方法装饰器上定义的东西，然后再组装成router对象即可
        glob(resolve(`${ apiPath }/*.ts`), (err, files) => {
            if (err !== null) {
                throw err;
            }
            files.forEach(file => {
                require(file);
            });
            methodArray.forEach(router => {
                const prefix = controllerMap.get(router.controller)?.path || "";
                this.router[router.method](prefix + router.path, router.handler);
            });
            this.app.use(this.router);
        });
    }
}

const controller: (path: string) => ClassDecorator = (path) => {
    console.log("Controller ClassDecorator:", path);
    return (target) => {
        if (!controllerMap.has(target.name)) {
            controllerMap.set(target.name, { path });
        }
    }
}

const get: (path: string) => MethodDecorator = (path:string) => {
    console.log("Get MethodDecorator");
    return (target, propertyKey, descriptor) => {
        methodArray.push({ controller: target.constructor.name, path, method: Method.get, handler: descriptor.value as unknown as RequestHandler })
    }
}
const post: (path: string) => MethodDecorator = (path:string) => {
    console.log("Post MethodDecorator");
    return (target, propertyKey, descriptor) => {
        methodArray.push({ controller: target.constructor.name, path, method: Method.post, handler: descriptor.value as unknown as RequestHandler })
    }
}


export {
    controller, get, post, Route
}
